package net.animats.music;

import java.util.ArrayList;
import java.util.List;

public class NoteSet {

    private IntervalSet intervalSet;
    private Note rootNote = null; // THE INDEX OF THE ROOT NOTE, IF IT IS KNOWN
    private List<Note> notes = new ArrayList<Note>();

    // CREATE THE NoteSet BY SPECIFYING THE ROOT Note AND THE IntervalSet
    public NoteSet(Note _rootNote, IntervalSet _intervalSet) {
        if (_rootNote == null) {
            System.out.println("null root note");
        } else {
            if (_intervalSet == null) {
                System.out.println("null interval set");
            } else {
                intervalSet = _intervalSet;

                // WHEN CREATED THIS WAY, THE TRUE ROOT NOTE IS KNOWN
                rootNote = _rootNote;

                // ITERATE THROUGH THE INTERVALS OF THIS CHORD TYPE
                // AND ADD THE EXTRA NOTES ABOVE THE ROOT NOTE
                for (Integer interval : intervalSet.getIntervals()) {
                    // GET THE INDEX OF THE ROOT NOTE AND
                    // ADD THE CURRENT INTERVAL TO IT
                    int noteIndex = _rootNote.getIndex();
                    noteIndex += interval;

                    // GET THE NOTE FOR THAT NEW INDEX AND
                    // ADD IT TO THIS CHORDS NOTES
                    notes.add(Note.getNote(noteIndex));
                }
            }
        }
    }

    public void transpose(int _delta) {
        if (getSize() == 0) {
            // EMPTY NoteSet SO DO NOTHING
            return;
        }

        List<Note> newNotes = new ArrayList<Note>();
        int index;

        for (Note currentNote : notes) {
            index = currentNote.getIndex();

            // FIND THE INDEX OF THE TRANSPOSED NOTE AND GET THE NEW NOTE
            index += _delta;
            newNotes.add(Note.getNote(index));
        }

        // SWAP THE OLD LIST FOR THE NEW LIST
        notes = newNotes;

        // ALSO TRANSPOSE THE ROOT NOTE IF IT IS KNOWN
        if (rootNote != null) {
            index = rootNote.getIndex();

            // FIND THE INDEX OF THE TRANSPOSED NOTE AND GET THE NEW NOTE
            index += _delta;
            rootNote = Note.getNote(index);
        }
    }

    public int getSize() {
        return notes.size();
    }

    public NoteSet(Note... _notes) {
        for (Note currentNote : _notes) {
            notes.add(currentNote);
        }
        syncIntervals();
    }

    private void syncIntervals() {
        if (intervalSet == null) {
            // THE INTERVALS AREN'T KNOWN, CREATE AN 'UNKNOWN' INTERVAL SET
            // FOR NOW AND TRY TO MATCH IT AGAINST A KNOWN SET LATER
            intervalSet = new IntervalSet("Unknown", "Unk");

        }
        intervalSet.syncIntervals(this);
    }

    public NoteSet() {
        // JUST CREATE AN EMPTY NoteSet
    }

    public boolean equals(Object _noteSet) {
        if (_noteSet instanceof NoteSet) {
            for (Note note : notes) {
                if (((NoteSet) _noteSet).getNotes().contains(note) == false) {
                    // THERE IS A NOTE IN THIS NoteSet THAT ISN'T
                    // IN THE PASSED NoteSet
                    return false;
                }
            }

            for (Note note : ((NoteSet) _noteSet).getNotes()) {
                if (notes.contains(note) == false) {
                    // THERE IS A NOTE IN THE PASSED NoteSet THAT ISN'T
                    // IN THIS NoteSet
                    return false;
                }
            }

            return true;

        } else {
            return false;
        }
    }

    public String toString() {
        if (notes.size() == 0) {
            return "Empty " + intervalSet.getName();
        }
        String output = notes.get(0).getName() + " " + intervalSet.getName() + ": ";
        for (Note note : notes) {
            output += note.getName() + " ";
        }

        return output;
    }

    public String getShortName() {
        if (notes.size() == 0) {
            return "Empty " + intervalSet.getName();
        }
        return getRootNote().getName() + intervalSet.getShortName();
    }

    public String getName() {
        if (notes.size() == 0) {
            return "Empty " + intervalSet.getName();
        }
        return getRootNote().getName() + " " + intervalSet.getName();
    }

    public void addNote(Note _note) {
        notes.add(_note);
        syncIntervals();
    }

    public void removeNote(Note _note) {
        notes.remove(_note);
        syncIntervals();
    }

    public void setRootNote(int _note) {
        if (_note > -1 && _note < notes.size()) {
            rootNote = notes.get(_note);
            syncIntervals();
        }
    }

    public Note getRootNote() {
        if (rootNote == null) {
            if (notes.size() > 0) {
                return notes.get(0);
            } else {
                return null;
            }
        } else {
            return rootNote;
        }
    }

    public List<Note> getNotes() {
        return notes;
    }

    public IntervalSet getIntervalSet() {
        return intervalSet;
    }

    public void setIntervalSet(IntervalSet _intervalSet) {
        intervalSet = _intervalSet;
    }
}
